/*
 * Copyright (C) <2009> 
 *
 * <Rishi B Agrawal> <Sneha Hendre>
 * <rishi.b.agrawal@gmail.com> <sneha.hendre@gmail.com>
 *
 * This program is free software: you can redistribute it and/or modify it 
 * under the terms of the GNU General Public License as published by the 
 * Free Software Foundation, either version 3 of the License, or (at your 
 * option) any later version->
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE->  See the
 * GNU General Public License for more details.
 *  
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include "../include/ohsm.h"
#include "ohsm_u.h"

int
parseinfo_device (xmlDocPtr doc, xmlNodePtr cur, unsigned int *tiers,  unsigned int *devices) {

	xmlChar *key;
	int no;
	unsigned int temp;
	int retval = 0;

	cur = cur->xmlChildrenNode;
	cur = cur->next;
	
	if ((!xmlStrcmp (cur->name, (const xmlChar *) "NR_TIERS"))) {
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if (temp == -1) {
				no = (int) xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <info><tiers> tag", no);
				printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
				xmlFree (key);
				return -1;
			} else {
				*tiers = temp;
			}
			
			if (*tiers > MAX_TIER_ALLOWED) {
				no = ( int )xmlGetLineNo(cur);
				printf("\nOHSM: [%d] : error Number of tiers entered more than ohsm supports", no);
				xmlFree (key);
				return -1;
			}		
			xmlFree (key);
	}
	cur = cur->next->next;	
	
	if ((!xmlStrcmp (cur->name, (const xmlChar *) "NR_DEVICES"))) {
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
	
			if (temp == -1) {
				no = (int) xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <info><devices> tag", no);
				printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
				xmlFree (key);
				return -1;
			} else {
				*devices = temp;
			}
			xmlFree (key);
	}
	return retval;
}


int 
parsetier (xmlDocPtr doc, xmlNodePtr cur, unsigned int devices) {
	
	xmlChar *key;
	char *temp_name = NULL;
	int retval = 0, cnt_devices = 0, no;
	unsigned int temp, ctr = 0, target = 0, major, minor;
	struct stat buf;

	cur = cur->xmlChildrenNode;
	cur = cur->next;
	while (cur != NULL) {
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "DEVICE"))) {
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			cnt_devices++;
			
			if (cnt_devices > devices) {
				printf("\nOHSM: number of devices in <info><devices> less than specified");
				return -1;
			} else {
				temp_name = (char *) key;
				retval = stat(temp_name,&buf);
				
				if (retval) {
					no = (int) xmlGetLineNo (cur);					
					printf("\nOHSM: [%d] : error device %s is not present", no, temp_name);
					return retval;
				}

				if (!S_ISBLK(buf.st_mode)) {
						no = (int) xmlGetLineNo (cur);					
						printf("\nOHSM: [%d] : error device %s is not valid block device", no, temp_name); 
					return -1;
				}
				
				major = MAJOR(buf.st_rdev);
        		minor = MINOR(buf.st_rdev);
				
				for (ctr = 0; ctr < dev_info->dinfo_count; ++ctr) {
					if (dev_info->device[ctr].dev_num == MKDEV(major, minor)) {
							strcpy(dev_info->device[ctr].dev_name, temp_name);	
							break;
					}		
				}		

				if (ctr >= dev_info->dinfo_count) {
					printf("\nOHSM: Invialid device specified.");
					return -1;
				}	
				target = ctr;
				xmlFree (key);
			}
		}
		cur = cur->next->next;
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "TIER"))){
			key = xmlNodeListGetString (doc, cur->xmlChildrenNode, 1);
			temp = validate_key (key);
			
			if (temp == -1) {
				no = (int)xmlGetLineNo (cur);
				printf("\nOHSM: [%d] : wrong value in <info><tiers> tag", no);
				printf("\nOHSM: [%d] : fatal : cannot proceed further", no);
				return -1;
			}	
			
			dev_info->device[target].tier = temp;
			xmlFree (key);
		}
		cur = cur->next->next;
	}
	
	if (cnt_devices < devices) {
		printf("\nOHSM: number of devices in <info><devices> greater than specified");
		return -1;
	}
	return 0;
}

int 
parsedoc_t (char *docname) {
	
	xmlDocPtr doc;
	xmlNodePtr cur;
	int retval = 0;
	unsigned int tiers, devices;
	
	doc = xmlParseFile (docname);
	if (!doc) {
		fprintf (stderr, "Document not parsed successfully. \n");
		xmlFreeDoc (doc);
		return -1;
	}
	
	cur = xmlDocGetRootElement (doc);
	if (!cur) {
		fprintf (stderr, "empty document\n");
		xmlFreeDoc (doc);
		return -1 ;
	}

	if (xmlStrcmp (cur->name, (const xmlChar *) "CREATE")){
		fprintf (stderr, "Invalid document Root element not equal to create...\n");
		xmlFreeDoc (doc);
		return -1;
	}

	cur = cur->xmlChildrenNode;
	cur = cur->next;	
	while (cur != NULL){
		
		if ((!xmlStrcmp (cur->name, (xmlChar *) "INFO"))){
			retval = parseinfo_device (doc, cur, &tiers, &devices);
			
			if (retval)
				return retval;
			dev_info->nr_tiers = tiers;
			dev_info->nr_devices = devices;
		}
		cur = cur->next->next;
		
		if ((!xmlStrcmp (cur->name, (const xmlChar *) "DEV_TIER"))){
			retval = parsetier (doc, cur, devices);
			 if (retval)
				 return retval;
		}
		cur = cur->next->next;
	}
	xmlFreeDoc (doc);
	return 0;
}

int 
ohsm_get_tier_device_info(char *filename) {

	int retval = 0;
	char cmd1[80];

	sprintf (cmd1,"xmllint --valid --noout %s",filename);	
	retval = system(cmd1);
	
	if (!retval) {
		retval = parsedoc_t (filename);
	}	
	return retval;
}

